home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / amitcp / netinet / in_pcb.c < prev    next >
C/C++ Source or Header  |  1993-08-12  |  15KB  |  508 lines

  1. RCS_ID_C="$Id: in_pcb.c,v 1.10 1993/06/04 11:16:15 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * HISTORY
  8.  * $Log: in_pcb.c,v $
  9.  * Revision 1.10  1993/06/04  11:16:15  jraja
  10.  * Fixes for first public release.
  11.  *
  12.  * Revision 1.9  1993/05/17  00:16:44  ppessi
  13.  * Changed RCS version. Added rcsid.
  14.  *
  15.  * Revision 1.8  1993/04/05  19:05:56  jraja
  16.  * Changed storage of the spl functions  return values to type spl_t.
  17.  * Added include for conf.h to every .c file.
  18.  *
  19.  * Revision 1.7  93/03/22  16:59:07  16:59:07  jraja (Jarno Tapio Rajahalme)
  20.  * Changed bcopy()s and bzero()s with word aligned pointers to
  21.  * aligned_b(copy|zero) ar aligned_b(copy|zero)_const. The latter is for calls
  22.  * in which the size is constant.
  23.  * These can be disabled by defining NOALIGN.
  24.  *  Converted bcopys doing structure copies (on aligned pointers) to structure
  25.  * assignments, since at least SASC produces better code with assignment.
  26.  * 
  27.  * Revision 1.6  93/03/13  17:14:18  17:14:18  ppessi (Pekka Pessi)
  28.  * Fixed bugs with variable initialization.
  29.  * 
  30.  * Revision 1.5  93/03/05  21:09:30  21:09:30  jraja (Jarno Tapio Rajahalme)
  31.  * Fixed includes (again).
  32.  * 
  33.  * Revision 1.4  93/03/05  03:19:49  03:19:49  ppessi (Pekka Pessi)
  34.  * Compiles with SASC. Initial test version.
  35.  * 
  36.  * Revision 1.3  93/03/04  12:10:15  12:10:15  jraja (Jarno Tapio Rajahalme)
  37.  * Added prototype includes.
  38.  * 
  39.  * Revision 1.2  93/02/26  08:58:25  08:58:25  jraja (Jarno Tapio Rajahalme)
  40.  * Made this compile with ANSI C.
  41.  * Addedinitialization of ifaddr in function in_pcbconnect, since it might
  42.  * have been used without.
  43.  * 
  44.  * Revision 1.1  92/11/17  16:28:57  16:28:57  jraja (Jarno Tapio Rajahalme)
  45.  * Initial revision
  46.  *
  47.  */
  48.  
  49. /*
  50.  * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
  51.  * All rights reserved.
  52.  *
  53.  * Redistribution and use in source and binary forms, with or without
  54.  * modification, are permitted provided that the following conditions
  55.  * are met:
  56.  * 1. Redistributions of source code must retain the above copyright
  57.  *    notice, this list of conditions and the following disclaimer.
  58.  * 2. Redistributions in binary form must reproduce the above copyright
  59.  *    notice, this list of conditions and the following disclaimer in the
  60.  *    documentation and/or other materials provided with the distribution.
  61.  * 3. All advertising materials mentioning features or use of this software
  62.  *    must display the following acknowledgement:
  63.  *    This product includes software developed by the University of
  64.  *    California, Berkeley and its contributors.
  65.  * 4. Neither the name of the University nor the names of its contributors
  66.  *    may be used to endorse or promote products derived from this software
  67.  *    without specific prior written permission.
  68.  *
  69.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  70.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  71.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  72.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  73.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  74.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  75.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  76.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  77.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  78.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  79.  * SUCH DAMAGE.
  80.  *
  81.  *    @(#)in_pcb.c    7.14 (Berkeley) 4/20/91
  82.  */
  83.  
  84. #include <conf.h>
  85.  
  86. #include <sys/param.h>
  87. #include <sys/systm.h>
  88. #include <sys/malloc.h>
  89. #include <sys/mbuf.h>
  90. #include <sys/protosw.h>
  91. #include <sys/socket.h>
  92. #include <sys/socketvar.h>
  93. #include <sys/ioctl.h>
  94.  
  95. #include <net/if.h>
  96. #include <net/route.h>
  97.  
  98. #include <netinet/in.h>
  99. #include <netinet/in_systm.h>
  100. #include <netinet/ip.h>
  101. #include <netinet/in_pcb.h>
  102. #include <netinet/in_var.h>
  103.  
  104. #include <netinet/in_protos.h>
  105. #include <netinet/in_pcb_protos.h>
  106. #include <kern/uipc_socket_protos.h>
  107. #include <net/rtsock_protos.h>
  108.  
  109. struct    in_addr zeroin_addr = {0};
  110.  
  111. int
  112. in_pcballoc(so, head)
  113.     struct socket *so;
  114.     struct inpcb *head;
  115. {
  116.     struct mbuf *m;
  117.     register struct inpcb *inp;
  118.  
  119.     m = m_getclr(M_DONTWAIT, MT_PCB);
  120.     if (m == NULL)
  121.         return (ENOBUFS);
  122.     inp = mtod(m, struct inpcb *);
  123.     inp->inp_head = head;
  124.     inp->inp_socket = so;
  125.     insque(inp, head);
  126.     so->so_pcb = (caddr_t)inp;
  127.     return (0);
  128. }
  129.     
  130. int
  131. in_pcbbind(inp, nam)
  132.     register struct inpcb *inp;
  133.     struct mbuf *nam;
  134. {
  135.     register struct socket *so = inp->inp_socket;
  136.     register struct inpcb *head = inp->inp_head;
  137.     register struct sockaddr_in *sin;
  138.     u_short lport = 0;
  139.  
  140.     if (in_ifaddr == 0)
  141.         return (EADDRNOTAVAIL);
  142.     if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
  143.         return (EINVAL);
  144.     if (nam == 0)
  145.         goto noname;
  146.     sin = mtod(nam, struct sockaddr_in *);
  147.     if (nam->m_len != sizeof (*sin))
  148.         return (EINVAL);
  149.     if (sin->sin_addr.s_addr != INADDR_ANY) {
  150.         int tport = sin->sin_port;
  151.  
  152.         sin->sin_port = 0;        /* yech... */
  153.         if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
  154.             return (EADDRNOTAVAIL);
  155.         sin->sin_port = tport;
  156.     }
  157.     lport = sin->sin_port;
  158.     if (lport) {
  159.         u_short aport = ntohs(lport);
  160.         int wild = 0;
  161.  
  162.         /* GROSS */
  163.         if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
  164.             return (EACCES);
  165.         /* even GROSSER, but this is the Internet */
  166.         if ((so->so_options & SO_REUSEADDR) == 0 &&
  167.             ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
  168.              (so->so_options & SO_ACCEPTCONN) == 0))
  169.             wild = INPLOOKUP_WILDCARD;
  170.         if (in_pcblookup(head,
  171.             zeroin_addr, 0, sin->sin_addr, lport, wild))
  172.             return (EADDRINUSE);
  173.     }
  174.     inp->inp_laddr = sin->sin_addr;
  175. noname:
  176.     if (lport == 0)
  177.         do {
  178.             if (head->inp_lport++ < IPPORT_RESERVED ||
  179.                 head->inp_lport > IPPORT_USERRESERVED)
  180.                 head->inp_lport = IPPORT_RESERVED;
  181.             lport = htons(head->inp_lport);
  182.         } while (in_pcblookup(head,
  183.                 zeroin_addr, 0, inp->inp_laddr, lport, 0));
  184.     inp->inp_lport = lport;
  185.     return (0);
  186. }
  187.  
  188. /*
  189.  * Connect from a socket to a specified address.
  190.  * Both address and port must be specified in argument sin.
  191.  * If don't have a local address for this socket yet,
  192.  * then pick one.
  193.  */
  194. int
  195. in_pcbconnect(inp, nam)
  196.     register struct inpcb *inp;
  197.     struct mbuf *nam;
  198. {
  199.     struct in_ifaddr *ia;
  200.     struct sockaddr_in *ifaddr = NULL;
  201.     register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
  202.  
  203.     if (nam->m_len != sizeof (*sin))
  204.         return (EINVAL);
  205.     if (sin->sin_family != AF_INET)
  206.         return (EAFNOSUPPORT);
  207.     if (sin->sin_port == 0)
  208.         return (EADDRNOTAVAIL);
  209.     if (in_ifaddr) {
  210.         /*
  211.          * If the destination address is INADDR_ANY,
  212.          * use the primary local address.
  213.          * If the supplied address is INADDR_BROADCAST,
  214.          * and the primary interface supports broadcast,
  215.          * choose the broadcast address for that interface.
  216.          */
  217. #define    satosin(sa)    ((struct sockaddr_in *)(sa))
  218.         if (sin->sin_addr.s_addr == INADDR_ANY)
  219.             sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
  220.         else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
  221.           (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
  222.             sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
  223.     }
  224.     if (inp->inp_laddr.s_addr == INADDR_ANY) {
  225.         register struct route *ro;
  226.         struct ifnet *ifp;
  227.  
  228.         ia = (struct in_ifaddr *)0;
  229.         /* 
  230.          * If route is known or can be allocated now,
  231.          * our src addr is taken from the i/f, else punt.
  232.          */
  233.         ro = &inp->inp_route;
  234.         if (ro->ro_rt &&
  235.             (satosin(&ro->ro_dst)->sin_addr.s_addr !=
  236.             sin->sin_addr.s_addr || 
  237.             inp->inp_socket->so_options & SO_DONTROUTE)) {
  238.             RTFREE(ro->ro_rt);
  239.             ro->ro_rt = (struct rtentry *)0;
  240.         }
  241.         if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
  242.             (ro->ro_rt == (struct rtentry *)0 ||
  243.             ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
  244.             /* No route yet, so try to acquire one */
  245.             ro->ro_dst.sa_family = AF_INET;
  246.             ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
  247.             ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
  248.                 sin->sin_addr;
  249.             rtalloc(ro);
  250.         }
  251.         /*
  252.          * If we found a route, use the address
  253.          * corresponding to the outgoing interface
  254.          * unless it is the loopback (in case a route
  255.          * to our address on another net goes to loopback).
  256.          */
  257.         if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
  258.             (ifp->if_flags & IFF_LOOPBACK) == 0)
  259.             for (ia = in_ifaddr; ia; ia = ia->ia_next)
  260.                 if (ia->ia_ifp == ifp)
  261.                     break;
  262.         if (ia == 0) {
  263.             int fport = sin->sin_port;
  264.  
  265.             sin->sin_port = 0;
  266.             ia = (struct in_ifaddr *)
  267.                 ifa_ifwithdstaddr((struct sockaddr *)sin);
  268.             sin->sin_port = fport;
  269.             if (ia == 0)
  270.                 ia = in_iaonnetof(in_netof(sin->sin_addr));
  271.             if (ia == 0)
  272.                 ia = in_ifaddr;
  273.             if (ia == 0)
  274.                 return (EADDRNOTAVAIL);
  275.         }
  276.         ifaddr = (struct sockaddr_in *)&ia->ia_addr;
  277.     }
  278.     if (in_pcblookup(inp->inp_head,
  279.         sin->sin_addr,
  280.         sin->sin_port,
  281.         inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
  282.         inp->inp_lport,
  283.         0))
  284.         return (EADDRINUSE);
  285.     if (inp->inp_laddr.s_addr == INADDR_ANY) {
  286.         if (inp->inp_lport == 0)
  287.             (void)in_pcbbind(inp, (struct mbuf *)0);
  288.         inp->inp_laddr = ifaddr->sin_addr;
  289.     }
  290.     inp->inp_faddr = sin->sin_addr;
  291.     inp->inp_fport = sin->sin_port;
  292.     return (0);
  293. }
  294.  
  295. void
  296. in_pcbdisconnect(inp)
  297.     struct inpcb *inp;
  298. {
  299.  
  300.     inp->inp_faddr.s_addr = INADDR_ANY;
  301.     inp->inp_fport = 0;
  302.     if (inp->inp_socket->so_state & SS_NOFDREF)
  303.         in_pcbdetach(inp);
  304. }
  305.  
  306. void
  307. in_pcbdetach(inp)
  308.     struct inpcb *inp;
  309. {
  310.     struct socket *so = inp->inp_socket;
  311.  
  312.     so->so_pcb = 0;
  313.     sofree(so);
  314.     if (inp->inp_options)
  315.         (void)m_free(inp->inp_options);
  316.     if (inp->inp_route.ro_rt)
  317.         rtfree(inp->inp_route.ro_rt);
  318.     remque(inp);
  319.     (void) m_free(dtom(inp));
  320. }
  321.  
  322. void
  323. in_setsockaddr(inp, nam)
  324.     register struct inpcb *inp;
  325.     struct mbuf *nam;
  326. {
  327.     register struct sockaddr_in *sin;
  328.     
  329.     nam->m_len = sizeof (*sin);
  330.     sin = mtod(nam, struct sockaddr_in *);
  331.     aligned_bzero_const((caddr_t)sin, sizeof (*sin));
  332.     sin->sin_family = AF_INET;
  333.     sin->sin_len = sizeof(*sin);
  334.     sin->sin_port = inp->inp_lport;
  335.     sin->sin_addr = inp->inp_laddr;
  336. }
  337.  
  338. void
  339. in_setpeeraddr(inp, nam)
  340.     struct inpcb *inp;
  341.     struct mbuf *nam;
  342. {
  343.     register struct sockaddr_in *sin;
  344.     
  345.     nam->m_len = sizeof (*sin);
  346.     sin = mtod(nam, struct sockaddr_in *);
  347.     aligned_bzero_const((caddr_t)sin, sizeof (*sin));
  348.     sin->sin_family = AF_INET;
  349.     sin->sin_len = sizeof(*sin);
  350.     sin->sin_port = inp->inp_fport;
  351.     sin->sin_addr = inp->inp_faddr;
  352. }
  353.  
  354. /*
  355.  * Pass some notification to all connections of a protocol
  356.  * associated with address dst.  The local address and/or port numbers
  357.  * may be specified to limit the search.  The "usual action" will be
  358.  * taken, depending on the ctlinput cmd.  The caller must filter any
  359.  * cmds that are uninteresting (e.g., no error in the map).
  360.  * Call the protocol specific routine (if any) to report
  361.  * any errors for each matching socket.
  362.  *
  363.  * Must be called at splnet.
  364.  */
  365. void
  366. in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
  367.     struct inpcb *head;
  368.     struct sockaddr *dst;
  369.     u_short fport, lport;
  370.     struct in_addr laddr;
  371.     int cmd;
  372.         void (* notify)(register struct inpcb * inp, int error);
  373. {
  374.     register struct inpcb *inp, *oinp;
  375.     struct in_addr faddr;
  376.     int errno;
  377.     extern u_char inetctlerrmap[];
  378.  
  379.     if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
  380.         return;
  381.     faddr = ((struct sockaddr_in *)dst)->sin_addr;
  382.     if (faddr.s_addr == INADDR_ANY)
  383.         return;
  384.  
  385.     /*
  386.      * Redirects go to all references to the destination,
  387.      * and use in_rtchange to invalidate the route cache.
  388.      * Dead host indications: notify all references to the destination.
  389.      * Otherwise, if we have knowledge of the local port and address,
  390.      * deliver only to that socket.
  391.      */
  392.     if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
  393.         fport = 0;
  394.         lport = 0;
  395.         laddr.s_addr = 0;
  396.         if (cmd != PRC_HOSTDEAD)
  397.             notify = in_rtchange;
  398.     }
  399.     errno = inetctlerrmap[cmd];
  400.     for (inp = head->inp_next; inp != head;) {
  401.         if (inp->inp_faddr.s_addr != faddr.s_addr ||
  402.             inp->inp_socket == 0 ||
  403.             (lport && inp->inp_lport != lport) ||
  404.             (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
  405.             (fport && inp->inp_fport != fport)) {
  406.             inp = inp->inp_next;
  407.             continue;
  408.         }
  409.         oinp = inp;
  410.         inp = inp->inp_next;
  411.         if (notify)
  412.             (*notify)(oinp, errno);
  413.     }
  414. }
  415.  
  416. /*
  417.  * Check for alternatives when higher level complains
  418.  * about service problems.  For now, invalidate cached
  419.  * routing information.  If the route was created dynamically
  420.  * (by a redirect), time to try a default gateway again.
  421.  */
  422. void
  423. in_losing(inp)
  424.     struct inpcb *inp;
  425. {
  426.     register struct rtentry *rt;
  427.  
  428.     if ((rt = inp->inp_route.ro_rt)) {
  429.         rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
  430.                 rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
  431.                 (struct sockaddr *)0, rt->rt_flags, 0);
  432.         if (rt->rt_flags & RTF_DYNAMIC)
  433.             (void) rtrequest(RTM_DELETE, rt_key(rt),
  434.                 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 
  435.                 (struct rtentry **)0);
  436.         inp->inp_route.ro_rt = 0;
  437.         rtfree(rt);
  438.         /*
  439.          * A new route can be allocated
  440.          * the next time output is attempted.
  441.          */
  442.     }
  443. }
  444.  
  445. /*
  446.  * After a routing change, flush old routing
  447.  * and allocate a (hopefully) better one.
  448.  */
  449. void
  450. in_rtchange(inp, error)
  451.     register struct inpcb *inp;
  452.         int error;
  453. {
  454.     if (inp->inp_route.ro_rt) {
  455.         rtfree(inp->inp_route.ro_rt);
  456.         inp->inp_route.ro_rt = 0;
  457.         /*
  458.          * A new route can be allocated the next time
  459.          * output is attempted.
  460.          */
  461.     }
  462. }
  463.  
  464. struct inpcb *
  465. in_pcblookup(head, faddr, fport, laddr, lport, flags)
  466.     struct inpcb *head;
  467.     struct in_addr faddr, laddr;
  468.     u_short fport, lport;
  469.     int flags;
  470. {
  471.     register struct inpcb *inp, *match = 0;
  472.     int matchwild = 3, wildcard;
  473.  
  474.     for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
  475.         if (inp->inp_lport != lport)
  476.             continue;
  477.         wildcard = 0;
  478.         if (inp->inp_laddr.s_addr != INADDR_ANY) {
  479.             if (laddr.s_addr == INADDR_ANY)
  480.                 wildcard++;
  481.             else if (inp->inp_laddr.s_addr != laddr.s_addr)
  482.                 continue;
  483.         } else {
  484.             if (laddr.s_addr != INADDR_ANY)
  485.                 wildcard++;
  486.         }
  487.         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  488.             if (faddr.s_addr == INADDR_ANY)
  489.                 wildcard++;
  490.             else if (inp->inp_faddr.s_addr != faddr.s_addr ||
  491.                 inp->inp_fport != fport)
  492.                 continue;
  493.         } else {
  494.             if (faddr.s_addr != INADDR_ANY)
  495.                 wildcard++;
  496.         }
  497.         if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
  498.             continue;
  499.         if (wildcard < matchwild) {
  500.             match = inp;
  501.             matchwild = wildcard;
  502.             if (matchwild == 0)
  503.                 break;
  504.         }
  505.     }
  506.     return (match);
  507. }
  508.